/**
 * 1、promise是一个类，在执行这个类的时候，需要传递一个执行器进去，执行器会立即执行
 * 2、Promise中有三个状态，分别为 成功 resolve、失败 rejected、等待 pedding
 *    状态一旦确定就不能被改变
 * 3、resolve和reject函数是用来更改状态的
 * 4、then方法做的事情就是判断状态，如果状态是成功，调用成功回调函数，
 *                               如果是失败，调用失败函数
 * 5、then方法是被定义在原型对象中
 * 6、then成功回调有一个参数，表示成功之后的值，失败回调有一个参数，表示失败的原因
 */
const PEDDING = 'pedding' //等待
const FULFILLED = 'fulfilled' //成功
const REJECTED = 'rejected' //失败

class MyPromise {

    //传递执行器，执行器立即执行
    constructor(exeuctor) {
        try {
            //console.log('myPromise')
            exeuctor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    //promise初始状态
    status = PEDDING

    //成功之后的值
    value = undefined
    //失败之后的原因
    reason = undefined

    //成功回调
    // successCallback = undefined  只能处理一个回调函数
    successCallback = []
    //失败回调
    // failCallback = undefined
    failCallback = []


    //使用箭头函数定义是为了执行方法的时候让this指向MyPromise的实例对象
    resolve = value => {
        //如果状态不是等待，阻止向下执行

        if (this.status !== PEDDING) return
        //将状态改为成功
        this.status = FULFILLED

        //记录成功方法接收的参数
        this.value = value

        //判断成功回调是否存在，如果存在则调用
        // this.successCallback && this.successCallback(this.value)
        //循环数组长度，从前往后依次执行其回调
        while (this.successCallback.length) {
            // this.successCallback.shift()(this.value)
            this.successCallback.shift()(this.value)
        }
    }

    reject = reason => {
        //将状态改为失败
        if (this.status !== PEDDING) return
        this.status = REJECTED


        //记录失败方法接收的参数
        this.reason = reason
        //判断失败回调是否存在，如果存在则调用
        // this.failCallback && this.failCallback(this.reason)
        //循环数组长度，从前往后依次执行其回调
        while (this.failCallback.length) {
            // this.failCallback.shift()(this.reason)
            this.failCallback.shift()(this.reason)
        }
    }
    //定义到原型对象上
    //then成功和失败都有个参数,然后把参数执行回调方法
    then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        let promisethen = new MyPromise((resolve, reject) => {
            //判断状态
            if (this.status === FULFILLED) {
                // let x = successCallback(this.value)


                setTimeout(() => {
                    //x接收上一个函数的返回值
                    try {
                        let x = successCallback(this.value)
                        //此处promisethen无法立即获取只能加settimout获取
                        resolvePromise(promisethen, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)

            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(promisethen, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else {
                //状态为pedding，等待
                // 将成功回调和失败回调存储起来，需要在属性里定义一下
                // this.successCallback.push(successCallback)
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value)
                            resolvePromise(promisethen, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                // this.failCallback.push(failCallback)
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.value)
                            resolvePromise(promisethen, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })
        return promisethen
    }

    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }

    catch(failCallback) {
        return this.then(undefined, failCallback)
    }


    static all(array) {
        let result = []
        let count = 0
        return new MyPromise((resolve, reject) => {

            function addData(index, value) {
                result[index] = value
                count++
                //console.log(count, array.length)
                if (count === array.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i]
                if (current instanceof MyPromise) {
                    // promise 对象
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }


    static resolve(value) {
        if (value instanceof MyPromise) {
            return value
        }
        return new MyPromise(resolve => resolve(value))
    }

}
//需要判断x的值是普通值还是promise对象,如果是普通值，直接调用resolve，
//如果是promise对象，查看promise的结果，根据promise对象返回的结果决定调用resolve，reject
function resolvePromise(promisethen, x, resolve, reject) {
    if (promisethen === x) {
        return reject(new TypeError("Chaining cycle detected for promise #<Promise>    "))
    }
    if (x instanceof MyPromise) {
        // promise 对象
        // x.then(value => resolve(value), reason => reject(reason));
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}

module.exports = MyPromise